package com.lagou.edu;

import com.lagou.edu.annotion.Autowired;
import com.lagou.edu.annotion.Component;
import com.lagou.edu.annotion.Service;
import com.lagou.edu.annotion.Transactional;
import com.lagou.edu.utils.ClassUtil;
import com.lagou.edu.utils.TransactionManager;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class BeanFactory {

    private static String BASE_PACKAGE = "com.lagou.edu";

    /**
     * Bean 的注册中心
     */
    public static Map<String, Object> singletonObjects = new HashMap<>();

    static {
        Set<Class<?>> set = ClassUtil.getClasses(BASE_PACKAGE);
        for (Class<?> clazz : set) {
            createBeanByClass(clazz);
        }
    }

    public static Object createBeanByClass(Class<?> clazz) {
        // 注解的处理
        Annotation beanAnno = null;
        String beanName = null;
        for (Annotation annotation : clazz.getAnnotations()) {
            boolean hasBeanAnno = (annotation.annotationType().getAnnotation(Component.class) != null) || (annotation instanceof Component);
            if (hasBeanAnno) {
                beanAnno = annotation;
                if (annotation instanceof Service) {
                    beanName = ((Service) annotation).value();
                } else {
                    beanName = ((Component) annotation).value();
                }
                break;
            }
        }

        if (beanAnno == null) {
            return null;
        }

        // bean标识转换
        if (beanName != null) {
            System.out.println(beanName);
            Type[] interfaces = clazz.getGenericInterfaces();
            if (null != interfaces && interfaces.length > 0) {
                firstLetterToLowCase(((Class) interfaces[0]).getSimpleName());
            } else {
                beanName = firstLetterToLowCase(clazz.getSimpleName());
            }
        }
        for (Map.Entry<String, Object> entry : singletonObjects.entrySet()) {
            // 类型匹配
            Type[] interfaces = entry.getValue().getClass().getGenericInterfaces();
            if (null != interfaces && interfaces.length > 0) {
                for (Type thisItf : interfaces) {
                    if (thisItf.equals(clazz)) {
                        return entry.getValue();
                    }
                }
            } else if (clazz.equals(entry.getValue().getClass())) {
                return entry.getValue();
            }
        }


        // 创建bean对象,并放入缓存池中
        Object beanObj = null;
        try {
            beanObj = createBean(clazz, beanName);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        singletonObjects.put(beanName, beanObj);
        return beanObj;
    }

    private static String firstLetterToLowCase(String name) {
        String first = name.substring(0, 1);
        String second = name.substring(1);
        return first.toLowerCase() + second;
    }

    /**
     * 反射创建对象
     *
     * @param thisClass
     * @return
     */
    private static Object createBean(Class<?> thisClass, String beanName) throws IllegalAccessException {

        // 创建bean
        Object originBean = doCreateBean(thisClass);
        // 提前曝光
        //earlySingletonObjects.put(beanName, earlySingletonObjects);

        // 填充bean属性
        populateBean(originBean, thisClass);

        // 完成对Bean的最后干预增强
        Object readyObject = initializeBean(beanName, originBean, thisClass);

        // 已经是个成熟的SpringBean了
        //earlySingletonObjects.remove(beanName);
        singletonObjects.put(beanName, readyObject);

        return readyObject;
    }

    /**
     * 简单实现,完成增强
     *
     * @param beanName
     * @param originBean
     * @return
     */
    private static Object initializeBean(String beanName, Object originBean, Class thisClass) throws IllegalAccessException {
        // 这里只考虑在类的方法上面加事务注解,不然要考虑类&方法上的事务注解的优先级
        for (Method thisMethod : thisClass.getDeclaredMethods()) {

            // 有事务注解的方法,进行事务增强
            if (thisMethod.isAnnotationPresent(Transactional.class)) {


                // 获取事务管理器
                TransactionManager transactionManage = (TransactionManager) getBean("transactionManage", TransactionManager.class);

                // jdk代理
                if (thisClass.getInterfaces() != null) {
                    return ProxyFactory.createJdkProxy(transactionManage, thisClass, originBean);
                } else {
                    return ProxyFactory.createCglibProxy(transactionManage, thisClass, originBean);
                }

            }
        }


        return originBean;
    }


    /**
     * 填充bean属性
     *
     * @param originBean
     * @param thisClass
     */
    private static void populateBean(Object originBean, Class<?> thisClass) throws IllegalAccessException {
        Field[] declaredFields = thisClass.getDeclaredFields();
        for (Field thisField : declaredFields) {

            // 判断是否有需要注入的属性
            if (thisField.isAnnotationPresent(Autowired.class)) {
                thisField.setAccessible(true);


                Boolean producedFlag = false;

                Class<?> fieldClass = thisField.getType();

                for (Map.Entry<String, Object> entry : singletonObjects.entrySet()) {

                    // 类型匹配
                    Type[] interfaces = entry.getValue().getClass().getGenericInterfaces();
                    if (null != interfaces && interfaces.length > 0) {
                        for (Type thisItf : interfaces) {
                            if (thisItf.equals(fieldClass)) {
                                thisField.set(originBean, entry.getValue());
                                producedFlag = true;
                                break;
                            }
                        }

                    }

                }
                if (!producedFlag) {
                    thisField.set(originBean, createBeanByClass(fieldClass));
                }

            }

        }


    }

    /**
     * 创建bean
     *
     * @param thisClass
     * @return
     */
    private static Object doCreateBean(Class<?> thisClass) {
        /**
         * 创建bean 方式有3种
         *  1.反射创建
         *  2.工厂模式创建:静态工厂和工厂方法
         *  3.FactoryBean:一般用于较复杂的创建过程
         */
        Object obj = null;
        try {
            obj = thisClass.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
        return obj;
    }

    public static synchronized Object getBean(String beanName, Class<?> beanClass) throws IllegalAccessException {
        Object cacheObj = singletonObjects.get(beanName);
        if (null == cacheObj) {

        }
        return createBean(beanClass, beanName);
    }


    public static Object getBean(String beanId) {
        return singletonObjects.get(beanId);
    }

    public static void main(String[] args) {
        System.out.println(BeanFactory.class);
    }


}
